#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "log.hpp"


int backlog = 10;

enum err
{
    Socketerr = 1,
    Bindeterr,
    Listeneterr, 
    Accepteterr, 
};

class Sock
{
public:
    //构造
    Sock()
    {}
    //析构
    ~Sock()
    {}

    //创建套接字
    void Socket()
    {
        sockfd_ = socket(AF_INET,SOCK_STREAM,0);
        if(sockfd_ < 0)
        {
            lg(FATAL,"Socket error: %d,%s",errno,strerror(errno));
            exit(Socketerr);
        }

    }

    //bind
    void Bind(uint16_t port)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        bzero(&peer,len);
        peer.sin_port = htons(port);
        peer.sin_family = AF_INET;
        peer.sin_addr.s_addr = INADDR_ANY;

        if(bind(sockfd_,(struct sockaddr *)&(peer),len) < 0)
        {
            lg(FATAL,"Bind error: %d,%s",errno,strerror(errno));
            exit(Bindeterr);
        }
    }

    //监听
    void Listen()
    {
        if(listen(sockfd_,backlog) < 0)
        {
            lg(FATAL,"Listen error: %d,%s",errno,strerror(errno));
            exit(Listeneterr);
        }
    }

    //接受
    int Accept(std::string * clientip,uint16_t* clientport)
    {
        struct sockaddr_in peer;
        socklen_t len  = sizeof(peer);
        bzero(&peer,len);

        int newfd = accept(sockfd_,(struct sockaddr*)&(peer),&len);
        if(newfd < 0)
        {
            lg(FATAL,"Accept error: %d,%s",errno,strerror(errno));
            exit(Accepteterr);
        }

        char ip[64];
        inet_ntop(AF_INET,&peer.sin_addr.s_addr,ip,sizeof(ip));
        *clientip = ip;
        *clientport = ntohs(peer.sin_port);
        
        return newfd;
    }

    //连接
    bool Connect(const std::string& ip,const uint16_t& port)
    {
        struct sockaddr_in peer;
        socklen_t len  = sizeof(peer);
        bzero(&peer,len);
        peer.sin_addr.s_addr = inet_addr(ip.c_str());
        peer.sin_port = htons(port);
        peer.sin_family = AF_INET;

        int n = connect(sockfd_,(struct sockaddr*)&(peer),len);
        if(n < 0)
        {
            lg(WARNING,"Connect error: %d,%s",errno,strerror(errno));
            return false;
        }

        return true;
    }

    void Close()
    {
        close(sockfd_);
    }

    //返回文件文件描述符
    int  GetFd()
    {
        return sockfd_;
    }


private:
    int sockfd_;
};

